#define NK_INCLUDE_FIXED_TYPES
#define NK_INCLUDE_STANDARD_IO
#define NK_INCLUDE_STANDARD_VARARGS
#define NK_INCLUDE_DEFAULT_ALLOCATOR
#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
#define NK_INCLUDE_FONT_BAKING
#define NK_INCLUDE_DEFAULT_FONT
#define NK_IMPLEMENTATION
#define NK_SDL_GL3_IMPLEMENTATION

#include "nuklear.h"
#include "nuklear_sdl_gl3.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600

#define LOW 15

// Game state
char board[LOW][LOW];
char currentPlayer;
int game_mode = 0; // 0: menu, 1: PvAI, 2: PvP
int game_over = 0;
char winner = ' ';
char status[256] = "Welcome to Wuzi! Select a mode to start.";

// AI-related variables from the original code
int singlePoint[LOW][LOW];
int single_low = 0;
int single_row = 0;
int max_score = 0;

// Function prototypes from the original code (refactored)
void Made_map(void);
int CheckWin(char player);
void DefensePoint(void);
void findMax(void);
void Single(int row, int col);
void CleanPoints(void);


void Made_map() {
    for (int i = 0; i < LOW; i++) {
        for (int j = 0; j < LOW; j++) {
            board[i][j] = '-';
        }
    }
}

void reset_game() {
    Made_map();
    currentPlayer = 'X';
    game_over = 0;
    winner = ' ';
    if (game_mode == 1) {
        strcpy(status, "Player 'X' vs AI 'Y'. Your turn.");
    } else if (game_mode == 2) {
        strcpy(status, "Player 'X' vs Player 'Y'. X's turn.");
    }
}

int main(int argc, char* argv[]) {
    /* Platform */
    SDL_Window *win;
    SDL_GLContext glContext;
    int win_width, win_height;

    /* GUI */
    struct nk_context *ctx;

    /* SDL setup */
    SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_EVENTS);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
    win = SDL_CreateWindow("Wuzi Game",
        SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
        WINDOW_WIDTH, WINDOW_HEIGHT,
        SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI);
    glContext = SDL_GL_CreateContext(win);
    SDL_GetWindowSize(win, &win_width, &win_height);

    /* GLEW setup */
    glewExperimental = 1;
    if (glewInit() != GLEW_OK) {
        fprintf(stderr, "Failed to setup GLEW\n");
        exit(1);
    }

    ctx = nk_sdl_init(win);
    /* Load Fonts: if none of these are loaded a default font will be used */
    struct nk_font_atlas *atlas;
    nk_sdl_font_stash_begin(&atlas);
    nk_sdl_font_stash_end();

    Made_map();
    currentPlayer = 'X';

    while (1) {
        /* Input */
        SDL_Event evt;
        nk_input_begin(ctx);
        while (SDL_PollEvent(&evt)) {
            if (evt.type == SDL_QUIT) goto cleanup;
            nk_sdl_handle_event(&evt);
        }
        nk_input_end(ctx);

        /* GUI */
        if (nk_begin(ctx, "Wuzi", nk_rect(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT), NK_WINDOW_NO_SCROLLBAR)) {
            // Menu Bar
            nk_layout_row_dynamic(ctx, 30, 4);
            if (nk_button_label(ctx, "New Game (vs AI)")) {
                game_mode = 1;
                reset_game();
            }
            if (nk_button_label(ctx, "New Game (vs Player)")) {
                game_mode = 2;
                reset_game();
            }
            if (nk_button_label(ctx, "Restart")) {
                 if(game_mode != 0) reset_game();
            }
            if (nk_button_label(ctx, "Quit")) {
                goto cleanup;
            }

            // Status Bar
            nk_layout_row_dynamic(ctx, 20, 1);
            nk_label(ctx, status, NK_TEXT_CENTERED);

            // Game Board
            nk_layout_row_dynamic(ctx, 500, 1);
            if (nk_group_begin(ctx, "BoardGroup", NK_WINDOW_BORDER)) {
                struct nk_command_buffer *canvas = nk_window_get_canvas(ctx);
                struct nk_rect total_space = nk_window_get_content_region(ctx);

                float board_size = (total_space.w < total_space.h) ? total_space.w : total_space.h;
                board_size -= 20; // padding
                float cell_size = board_size / LOW;
                struct nk_rect board_rect = { total_space.x + 10, total_space.y + 10, board_size, board_size };

                // Draw board lines
                for (int i = 0; i < LOW; i++) {
                    nk_stroke_line(canvas, board_rect.x + i * cell_size, board_rect.y, board_rect.x + i * cell_size, board_rect.y + board_size - cell_size, 1.0f, nk_rgb(0,0,0));
                    nk_stroke_line(canvas, board_rect.x, board_rect.y + i * cell_size, board_rect.x + board_size - cell_size, board_rect.y + i * cell_size, 1.0f, nk_rgb(0,0,0));
                }

                // Draw pieces and handle input
                for (int i = 0; i < LOW; i++) {
                    for (int j = 0; j < LOW; j++) {
                        float piece_x = board_rect.x + j * cell_size - cell_size / 2;
                        float piece_y = board_rect.y + i * cell_size - cell_size / 2;
                        struct nk_rect piece_rect = { piece_x, piece_y, cell_size, cell_size };

                        if (board[i][j] != '-') {
                            struct nk_color color = (board[i][j] == 'X') ? nk_rgb(0,0,0) : nk_rgb(255,255,255);
                            nk_fill_circle(canvas, piece_rect, color);
                            nk_stroke_circle(canvas, piece_rect, 1.0f, nk_rgb(0,0,0));
                        }

                        if (!game_over && game_mode != 0 && nk_input_is_mouse_hovering_rect(&ctx->input, piece_rect)) {
                            if (nk_input_is_mouse_pressed(&ctx->input, NK_BUTTON_LEFT)) {
                                if (board[i][j] == '-') {
                                    board[i][j] = currentPlayer;
                                    if (CheckWin(currentPlayer)) {
                                        game_over = 1;
                                        winner = currentPlayer;
                                        sprintf(status, "Player %c wins!", winner);
                                    } else {
                                        if (game_mode == 2) { // PvP
                                            currentPlayer = (currentPlayer == 'X') ? 'Y' : 'X';
                                            sprintf(status, "Player %c's turn.", currentPlayer);
                                        } else { // PvAI
                                            // AI's turn
                                            CleanPoints();
                                            DefensePoint();
                                            findMax();
                                            Single(i, j); // Pass player's move for context
                                            if (CheckWin('Y')) {
                                                game_over = 1;
                                                winner = 'Y';
                                                strcpy(status, "AI 'Y' wins!");
                                            } else {
                                                 strcpy(status, "Player 'X's turn.");
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                nk_group_end(ctx);
            }
        }
        nk_end(ctx);

        /* Draw */
        SDL_GetWindowSize(win, &win_width, &win_height);
        glViewport(0, 0, win_width, win_height);
        glClear(GL_COLOR_BUFFER_BIT);
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        nk_sdl_render(NK_ANTI_ALIASING_ON, 512 * 1024, 128 * 1024);
        SDL_GL_SwapWindow(win);
    }

cleanup:
    nk_sdl_shutdown();
    SDL_GL_DeleteContext(glContext);
    SDL_DestroyWindow(win);
    SDL_Quit();
    return 0;
}

// =================================================================================================
// Ported and refactored game logic from the original main.c
// Note: All printf calls have been removed and logic adapted for the GUI.
// =================================================================================================

int CheckWin(char player) {
    // Horizontal check
    for (int i = 0; i < LOW; i++) {
        for (int j = 0; j < LOW - 4; j++) {
            if (board[i][j] == player && board[i][j + 1] == player && board[i][j + 2] == player &&
                board[i][j + 3] == player && board[i][j + 4] == player) {
                return 1;
            }
        }
    }
    // Vertical check
    for (int i = 0; i < LOW - 4; i++) {
        for (int j = 0; j < LOW; j++) {
            if (board[i][j] == player && board[i + 1][j] == player && board[i + 2][j] == player &&
                board[i + 3][j] == player && board[i + 4][j] == player) {
                return 1;
            }
        }
    }
    // Diagonal (top-left to bottom-right)
    for (int i = 0; i < LOW - 4; i++) {
        for (int j = 0; j < LOW - 4; j++) {
            if (board[i][j] == player && board[i + 1][j + 1] == player && board[i + 2][j + 2] == player &&
                board[i + 3][j + 3] == player && board[i + 4][j + 4] == player) {
                return 1;
            }
        }
    }
    // Diagonal (bottom-left to top-right)
    for (int i = 4; i < LOW; i++) {
        for (int j = 0; j < LOW - 4; j++) {
            if (board[i][j] == player && board[i - 1][j + 1] == player && board[i - 2][j + 2] == player &&
                board[i - 3][j + 3] == player && board[i - 4][j + 4] == player) {
                return 1;
            }
        }
    }
    return 0;
}

void CleanPoints() {
    for (int i = 0; i < LOW; ++i) {
        for (int j = 0; j < LOW; ++j) {
            singlePoint[i][j] = 0;
        }
    }
}

// The AI logic is complex and seems to be based on pattern matching.
// This is a direct port. It could be simplified, but for now, we keep it as is.
void DefensePoint() {
    // This is a simplified port of the original AI logic.
    // It scores moves for both player 'X' (to block) and AI 'Y' (to win).
    char players[] = {'X', 'Y'};
    int scores[] = {400, 500}; // defense score, offense score

    for (int p = 0; p < 2; ++p) {
        char player = players[p];
        int score_val = scores[p];

        for (int i = 0; i < LOW; i++) {
            for (int j = 0; j < LOW; j++) {
                if (board[i][j] != '-') continue;

                // Horizontal
                int count = 0;
                for(int k = 1; k < 5; ++k) if(j + k < LOW && board[i][j+k] == player) count++; else break;
                for(int k = 1; k < 5; ++k) if(j - k >= 0 && board[i][j-k] == player) count++; else break;
                if(count >= 4) singlePoint[i][j] += score_val;

                // Vertical
                count = 0;
                for(int k = 1; k < 5; ++k) if(i + k < LOW && board[i+k][j] == player) count++; else break;
                for(int k = 1; k < 5; ++k) if(i - k >= 0 && board[i-k][j] == player) count++; else break;
                if(count >= 4) singlePoint[i][j] += score_val;

                // Diagonal \
                count = 0;
                for(int k = 1; k < 5; ++k) if(i + k < LOW && j + k < LOW && board[i+k][j+k] == player) count++; else break;
                for(int k = 1; k < 5; ++k) if(i - k >= 0 && j - k >= 0 && board[i-k][j-k] == player) count++; else break;
                if(count >= 4) singlePoint[i][j] += score_val;

                // Diagonal /
                count = 0;
                for(int k = 1; k < 5; ++k) if(i + k < LOW && j - k >= 0 && board[i+k][j-k] == player) count++; else break;
                for(int k = 1; k < 5; ++k) if(i - k >= 0 && j + k < LOW && board[i-k][j+k] == player) count++; else break;
                if(count >= 4) singlePoint[i][j] += score_val;
            }
        }
    }
}


void findMax() {
    max_score = 0;
    single_low = -1;
    single_row = -1;

    for (int i = 0; i < LOW; i++) {
        for (int j = 0; j < LOW; j++) {
            if (board[i][j] == '-' && singlePoint[i][j] > max_score) {
                max_score = singlePoint[i][j];
                single_low = i;
                single_row = j;
            }
        }
    }
}

void Single(int row, int col) {
    if (single_low != -1 && single_row != -1) {
        board[single_low][single_row] = 'Y';
    } else {
        // If no strategic point is found, play next to the player's last move
        for (int i = -1; i <= 1; i++) {
            for (int j = -1; j <= 1; j++) {
                if (i == 0 && j == 0) continue;
                int r = row + i;
                int c = col + j;
                if (r >= 0 && r < LOW && c >= 0 && c < LOW && board[r][c] == '-') {
                    board[r][c] = 'Y';
                    return;
                }
            }
        }
        // If all surrounding cells are occupied, find the first empty cell
        for (int i = 0; i < LOW; i++) {
            for (int j = 0; j < LOW; j++) {
                if (board[i][j] == '-') {
                    board[i][j] = 'Y';
                    return;
                }
            }
        }
    }
}